/* #include <stdio.h>
#include <pthread.h>
#include <unistd.h>

int count = 0;

void *Routine(void *arg)
{
    while (1)
    {
        sleep(1);
        count++;
    }
    pthread_exit((void *)0);
}

int main()
{
    pthread_t tid;
    pthread_create(&tid, NULL, Routine, NULL);

    while (1)
    {
        sleep(1);
        printf("count: %d\n", count);
    }

    pthread_join(tid, NULL);
    return 0;
} */

/* #include <stdio.h>
#include <unistd.h>
#include <pthread.h>

int tickets = 100;

void *TicketGrabbing(void *arg)
{
    const char *name = (char *)arg;
    while (1)
    {
        if (tickets > 0)
        {
            usleep(10000);
            printf("[%s] get a ticket, left: %d\n", name, --tickets);
        }
        else
        {
            break;
        }
    }

    printf("%s quit!\n", name);
    pthread_exit((void *)0);
}

int main()
{
    pthread_t t1, t2, t3, t4;
    pthread_create(&t1, NULL, TicketGrabbing, (void *)"thread 1");
    pthread_create(&t2, NULL, TicketGrabbing, (void *)"thread 2");
    pthread_create(&t3, NULL, TicketGrabbing, (void *)"thread 3");
    pthread_create(&t4, NULL, TicketGrabbing, (void *)"thread 4");

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_join(t4, NULL);
    return 0;
} */

/* #include <stdio.h>
#include <unistd.h>
#include <pthread.h>

int tickets = 1000;
// 1. 定义一把全局的互斥锁, 并使用宏进行静态初始化
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

void *TicketGrabbing(void *arg)
{
    const char *name = (char *)arg;
    while (1)
    {
        // 2. 在进入临界区之前，所有线程都必须先尝试加锁
        pthread_mutex_lock(&lock);

        if (tickets > 0)
        {
            // --- 临界区开始 ---
            usleep(10000); // 即使有延时，数据也是安全的
            printf("[%s] get a ticket, left: %d\n", name, --tickets);
            // --- 临界区结束 ---

            // 3. 操作完成，必须解锁，让其他等待的线程有机会进入
            pthread_mutex_unlock(&lock);
        }
        else
        {
            // 4. [至关重要!] 发现票已卖完，在退出循环前也必须解锁
            // 否则，如果一个线程在这里break了，它将永远持有锁，
            // 其他线程将永远阻塞在第19行的lock调用上，造成死锁。
            pthread_mutex_unlock(&lock);
            break;
        }
    }

    printf("%s quit!\n", name);
    pthread_exit((void *)0);
}

int main()
{
    pthread_t t1, t2, t3, t4;
    pthread_create(&t1, NULL, TicketGrabbing, (void *)"thread 1");
    pthread_create(&t2, NULL, TicketGrabbing, (void *)"thread 2");
    pthread_create(&t3, NULL, TicketGrabbing, (void *)"thread 3");
    pthread_create(&t4, NULL, TicketGrabbing, (void *)"thread 4");

    pthread_join(t1, NULL);
    pthread_join(t2, NULL);
    pthread_join(t3, NULL);
    pthread_join(t4, NULL);

    // 在所有线程结束后，打印最终的票数来验证结果
    printf("All threads finished. Final tickets left: %d\n", tickets);
    return 0;
} */

#include <iostream>
#include <vector>
#include <string>
#include <unistd.h>
#include <pthread.h>

#define NUM 5
int cnt = 1000;

pthread_mutex_t glock = PTHREAD_MUTEX_INITIALIZER; // 定义全局互斥锁
pthread_cond_t gcond = PTHREAD_COND_INITIALIZER;   // 定义全局条件变量

void *threadrun(void *args)
{
    std::string name = static_cast<const char *>(args);
    while (true)
    {
        // 1. 线程首先必须加锁，以保护对条件的检查（尽管本例中没有显式检查）
        pthread_mutex_lock(&glock);

        // 2. 线程在此条件变量上等待
        //    调用此函数时，它会自动释放glock，并使线程睡眠
        //    当被唤醒时，它会自动重新获取glock，然后才返回
        pthread_cond_wait(&gcond, &glock);

        // 3. 被唤醒后，线程执行其任务
        std::cout << name << " has been woken up, cnt: " << cnt << std::endl;
        cnt++;

        // 4. 任务完成，释放锁
        pthread_mutex_unlock(&glock);
    }
}

int main()
{
    std::vector<pthread_t> threads;
    for (int i = 0; i < NUM; i++)
    {
        pthread_t tid;
        char *name = new char[64];
        snprintf(name, 64, "thread-%d", i);
        pthread_create(&tid, nullptr, threadrun, name);
        threads.push_back(tid);
        sleep(1); // 在线程创建之间加入延时，确保它们有序启动并进入等待
    }

    // 等待足够长的时间，确保所有工作线程都已启动并调用了pthread_cond_wait
    sleep(3);

    // 主线程在一个循环中，周期性地唤醒工作线程
    while (true)
    {
        /* // 场景一：使用 broadcast 唤醒所有线程
        std::cout << "Main thread broadcasting..." << std::endl;
        pthread_cond_broadcast(&gcond); */

        // 场景二：使用 signal 唤醒一个线程
        std::cout << "Main thread signaling..." << std::endl;
        pthread_cond_signal(&gcond);
        sleep(1);
    }

    for (auto &id : threads)
    {
        pthread_join(id, nullptr);
    }

    return 0;
}